<template>
  <div class="waterfall-container" ref="containerRef">
    <slot />
  </div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue';

/**
 * @description 瀑布流布局组件
 * @param {Number} columnCount 列数
 * @param {Number} columnGap 列间距
 * @param {Number} rowGap 行间距
 */
const props = defineProps({
  columnCount: {
    type: Number,
    default: 3
  },
  columnGap: {
    type: Number,
    default: 10
  },
  rowGap: {
    type: Number,
    default: 10
  }
});

const containerRef = ref(null);

const layoutWaterfall = () => {
  if (!containerRef.value) return;
  const container = containerRef.value;
  const items = Array.from(container.children);
  const { columnCount, columnGap, rowGap } = props;

  // 初始化每列的高度数组
  const columnHeights = new Array(columnCount).fill(0);

  // 先设置元素宽度
  const itemWidth = (container.offsetWidth - (columnCount - 1) * columnGap) / columnCount;
  items.forEach(item => {
    item.style.width = `${itemWidth}px`;
    // 强制重新计算布局，确保获取正确的offsetHeight
    void item.offsetWidth;
  });

  items.forEach(item => {
    // 找到当前高度最小的列
    let minHeightColumnIndex = 0;
    for (let i = 1; i < columnCount; i++) {
      if (columnHeights[i] < columnHeights[minHeightColumnIndex]) {
        minHeightColumnIndex = i;
      }
    }

    // 设置元素的位置
    item.style.position = 'absolute';
    item.style.left = `${minHeightColumnIndex * (itemWidth + columnGap)}px`;
    item.style.top = `${columnHeights[minHeightColumnIndex]}px`;

    // 更新该列的高度
    columnHeights[minHeightColumnIndex] += item.offsetHeight + rowGap;
  });

  // 设置容器的高度
  const maxHeight = Math.max(...columnHeights);
  container.style.height = `${maxHeight - rowGap}px`;
};

const resizeObserver = new ResizeObserver(() => {
  layoutWaterfall();
});

onMounted(() => {
  if (containerRef.value) {
    layoutWaterfall();
    resizeObserver.observe(containerRef.value);
  }
});

watch(
    () => [props.columnCount, props.columnGap, props.rowGap],
    () => {
      layoutWaterfall();
    },
    { deep: true }
);
</script>

<style scoped>
.waterfall-container {
  position: relative;
}

.waterfall-container > * {
  break-inside: avoid;
  box-sizing: border-box;
}
</style>